#include "tle.h"
#include "tleexception.h"
#include <locale>

namespace libsgp4
{
namespace
{
//  COL表示各字段的开始列数，LEN是该字段的长度
static const unsigned int TLE1_COL_NORADNUM = 2;
static const unsigned int TLE1_LEN_NORADNUM = 5;
static const unsigned int TLE1_COL_INTLDESC_A = 9;
static const unsigned int TLE1_LEN_INTLDESC_A = 2;
//  static const unsigned int TLE1_COL_INTLDESC_B = 11;
static const unsigned int TLE1_LEN_INTLDESC_B = 3;
//  static const unsigned int TLE1_COL_INTLDESC_C = 14;
static const unsigned int TLE1_LEN_INTLDESC_C = 3;
static const unsigned int TLE1_COL_EPOCH_A = 18;
static const unsigned int TLE1_LEN_EPOCH_A = 2;
static const unsigned int TLE1_COL_EPOCH_B = 20;
static const unsigned int TLE1_LEN_EPOCH_B = 12;
static const unsigned int TLE1_COL_MEANMOTIONDT2 = 33;
static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 10;
static const unsigned int TLE1_COL_MEANMOTIONDDT6 = 44;
static const unsigned int TLE1_LEN_MEANMOTIONDDT6 = 8;
static const unsigned int TLE1_COL_BSTAR = 53;
static const unsigned int TLE1_LEN_BSTAR = 8;
//  static const unsigned int TLE1_COL_EPHEMTYPE = 62;
//  static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
//  static const unsigned int TLE1_COL_ELNUM = 64;
//  static const unsigned int TLE1_LEN_ELNUM = 4;

static const unsigned int TLE2_COL_NORADNUM = 2;
static const unsigned int TLE2_LEN_NORADNUM = 5;
static const unsigned int TLE2_COL_INCLINATION = 8;
static const unsigned int TLE2_LEN_INCLINATION = 8;
static const unsigned int TLE2_COL_RAASCENDNODE = 17;
static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
static const unsigned int TLE2_COL_ECCENTRICITY = 26;
static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
static const unsigned int TLE2_COL_ARGPERIGEE = 34;
static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
static const unsigned int TLE2_COL_MEANANOMALY = 43;
static const unsigned int TLE2_LEN_MEANANOMALY = 8;
static const unsigned int TLE2_COL_MEANMOTION = 52;
static const unsigned int TLE2_LEN_MEANMOTION = 11;
static const unsigned int TLE2_COL_REVATEPOCH = 63;
static const unsigned int TLE2_LEN_REVATEPOCH = 5;
}

/**
 * Initialise the tle object.
 * @exception TleException
 * 初始化，在非法时抛出报错
 */
void Tle::Initialize()
{
    if (!IsValidLineLength(line_one_))
    {
        std::cout << line_one_;
        throw TleException("Invalid length for line one");
    }

    if (!IsValidLineLength(line_two_))
    {
        throw TleException("Invalid length for line two");
    }

    if (line_one_[0] != '1')
    {
        throw TleException("Invalid line beginning for line one");
    }

    if (line_two_[0] != '2')
    {
        throw TleException("Invalid line beginning for line two");
    }

    unsigned int sat_number_1;
    unsigned int sat_number_2;

    ExtractInteger(line_one_.substr(TLE1_COL_NORADNUM,
                                    TLE1_LEN_NORADNUM), sat_number_1);
    ExtractInteger(line_two_.substr(TLE2_COL_NORADNUM,
                                    TLE2_LEN_NORADNUM), sat_number_2);

    if (sat_number_1 != sat_number_2)
    {
        throw TleException("Satellite numbers do not match");
    }

    norad_number_ = sat_number_1;

    if (name_.empty())
    {
        name_ = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM);
    }

    int_designator_ = line_one_.substr(TLE1_COL_INTLDESC_A,
                                       TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);

    unsigned int year = 0;
    double day = 0.0;

    ExtractInteger(line_one_.substr(TLE1_COL_EPOCH_A,
                                    TLE1_LEN_EPOCH_A), year);
    ExtractDouble(line_one_.substr(TLE1_COL_EPOCH_B,
                                   TLE1_LEN_EPOCH_B), 4, day);
    ExtractDouble(line_one_.substr(TLE1_COL_MEANMOTIONDT2,
                                   TLE1_LEN_MEANMOTIONDT2), 2, mean_motion_dt2_);
    ExtractExponential(line_one_.substr(TLE1_COL_MEANMOTIONDDT6,
                                        TLE1_LEN_MEANMOTIONDDT6), mean_motion_ddt6_);
    ExtractExponential(line_one_.substr(TLE1_COL_BSTAR,
                                        TLE1_LEN_BSTAR), bstar_);

    /*
     * line 2
     */
    ExtractDouble(line_two_.substr(TLE2_COL_INCLINATION,
                                   TLE2_LEN_INCLINATION), 4, inclination_);
    ExtractDouble(line_two_.substr(TLE2_COL_RAASCENDNODE,
                                   TLE2_LEN_RAASCENDNODE), 4, right_ascending_node_);
    ExtractDouble(line_two_.substr(TLE2_COL_ECCENTRICITY,
                                   TLE2_LEN_ECCENTRICITY), -1, eccentricity_);
    ExtractDouble(line_two_.substr(TLE2_COL_ARGPERIGEE,
                                   TLE2_LEN_ARGPERIGEE), 4, argument_perigee_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANANOMALY,
                                   TLE2_LEN_MEANANOMALY), 4, mean_anomaly_);
    ExtractDouble(line_two_.substr(TLE2_COL_MEANMOTION,
                                   TLE2_LEN_MEANMOTION), 3, mean_motion_);
    ExtractInteger(line_two_.substr(TLE2_COL_REVATEPOCH,
                                    TLE2_LEN_REVATEPOCH), orbit_number_);

    if (year < 57)
    {
        year += 2000;
    }
    else
    {
        year += 1900;
    }

    epoch_ = DateTime(year, day);
}

/**
 * 检查
 * @param str 待检查字符串
 * @returns 字符串长度是否合法
 */
bool Tle::IsValidLineLength(const std::string& str)
{
    return str.length() == LineLength() ? true : false;
}

/**
 * 对包含整数的字符串进行提取
 * @param[in] str 待处理的字符串
 * @param[out] val 结果
 * @exception TleException出错时抛出
 */
void Tle::ExtractInteger(const std::string& str, unsigned int& val)
{
    bool found_digit = false;// 标记是否找到了数字
    unsigned int temp = 0;// 用于临时存储提取的数字

    for (auto& i : str)
    {
        if (isdigit(i))
        {
            found_digit = true;
            temp = (temp * 10) + static_cast<unsigned int>(i - '0');
            // 将当前数字字符转换为对应的整数值，并累加到temp中（考虑到了之前的数字）
        }
        else if (found_digit)
        {
            throw TleException("Unexpected non digit");
        }
        else if (i != ' ')
        {
            throw TleException("Invalid character");
        }
    }

    if (!found_digit)
    {
        val = 0;
    }
    else
    {
        val = temp;
    }
}

/**
 * 对包含含小数的浮点数（double类型）的字符串进行提取
 * @param[in] str 待处理的字符串
 * @param[in] point_pos 小数点的位置（如果没有小数点则为-1）
 * @param[out] val 结果
 * @exception TleException出错时抛出
 */
void Tle::ExtractDouble(const std::string& str, int point_pos, double& val)
{
    std::string temp;
    bool found_digit = false;

    for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
    {
        /*
         * 解析整数部分
         */
        if (point_pos >= 0 && i < str.begin() + point_pos - 1)
        {
            bool done = false;

            if (i == str.begin())
            {
                if(*i == '-' || *i == '+')
                {
                    /*
                     * 字符串的第一个字符，可能是正负号
                     */
                    temp += *i;
                    done = true;
                }
            }

            if (!done)
            {
                if (isdigit(*i))
                {
                    found_digit = true;
                    temp += *i;
                }
                else if (found_digit)
                {
                    throw TleException("Unexpected non digit");
                }
                else if (*i != ' ')
                {
                    throw TleException("Invalid character");
                }
            }
        }
        /*
         * 小数点
         */
        else if (point_pos >= 0 && i == str.begin() + point_pos - 1)
        {
            if (temp.length() == 0)
            {
                /*
                 * 如果整数部分为空，则添加 '0'
                 */
                temp += '0';
            }

            if (*i == '.')
            {
                /*
                 * 找小数点
                 */
                temp += *i;
            }
            else
            {
                throw TleException("Failed to find decimal point");
            }
        }
        /*
         * 解析小数部分
         */
        else
        {
            if (i == str.begin() && point_pos == -1)
            {
                /*
                 * 如果字符串以小数点开头且没有指定小数点位置，则添加 '0.'
                 */
                temp += '0';
                temp += '.';
            }

            /*
             * 当前字符应为数字
             */
            if (isdigit(*i))
            {
                temp += *i;
            }
            else
            {
                throw TleException("Invalid digit");
            }
        }
    }

    if (!Util::FromString<double>(temp, val))
    {
        throw TleException("Failed to convert value to double");
    }
}

/**
 * 从字符串提取并转换一个指数形式的数值。
 * 在TLE数据中，虽然直接给出的数值通常不是以指数形式呈现，
 * 但某些参数（如阻力系数B*）实际上是科学计数法表示，它的中间有一个+/-，其实是省略了e。
 * @param[in] str 输入字符串
 * @param[out] val 输出字符串
 * @exception TleException出错时抛出
 */
// void Tle::ExtractExponential(const std::string& str, double& val)
// {
//     std::string temp;

//     for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
//     {
//         if (i == str.begin())
//         {
//             if (*i == '-' || *i == '+' || *i == ' ')
//             {
//                 if (*i == '-')
//                 {
//                     temp += *i;
//                 }
//                 temp += '0';
//                 temp += '.';
//             }
//             else
//             {
//                 throw TleException("Invalid sign");
//             }
//         }
//         else if (i == str.end() - 2)
//         {
//             if (*i == '-' || *i == '+')
//             {
//                 temp += 'e';
//                 temp += *i;
//             }
//             else
//             {
//                 throw TleException("Invalid exponential sign");
//             }
//         }
//         else
//         {
//             if (isdigit(*i))
//             {
//                 temp += *i;
//             }
//             else
//             {
//                 throw TleException("Invalid digit");
//             }
//         }
//     }

//     if (!Util::FromString<double>(temp, val))
//     {
//         throw TleException("Failed to convert value to double");
//     }
// }


void Tle::ExtractExponential(const std::string& str, double& val)
{

    std::string temp;
    bool hasDecimal = false, hasExponent = false;

    for (size_t i = 0; i < str.length(); ++i) {
        char c = str[i];

        // 跳过前导空格
        if (temp.empty() && c == ' ') continue;

        // 处理符号和数字
        if (isdigit(c) || c == '-' || c == '+') {
            // 自动补全缺失的小数点
            if (!hasDecimal && temp.find('.') == std::string::npos &&
                isdigit(c) && i > 0 && isdigit(str[i-1])) {
                temp += '.';
                hasDecimal = true;
            }
            temp += c;
        } else if ((c == 'e' || c == 'E') && !hasExponent) {
            temp += 'e';
            hasExponent = true;
        } else if (c == '.' && !hasDecimal) {
            temp += c;
            hasDecimal = true;
        }
    }

    // 格式校验（新增）
    if (temp.empty() || temp == ".")
        throw TleException("Empty B* value");

    try {
        val = std::stod(temp);
    } catch (const std::exception& e) {
        throw TleException("B*格式转换失败:");
    }
}

} // namespace libsgp4

